package com.rr.mymoney.upload.parser;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

import com.rr.mymoney.upload.ImportData;
import com.rr.mymoney.utils.ClassLister;

public class GenericFileUploadParser {
    private static transient Logger log = Logger.getLogger(GenericFileUploadParser.class);
    private static List<Class<? extends BankAccountTransactionsParser>> transactionsParser;
    static {
	findTransactionParsers();
    }

    public ImportData parse(InputStream fis) throws Exception {

	ImportData importData = null;

	try {
	    // Create an excel workbook from the file system.
	    Workbook workbook = null;
	    try {
		workbook = WorkbookFactory.create(fis);
	    } catch (Exception e) {
		log.error("Excel file read error:", e);
	    }

	    for (Class<? extends BankAccountTransactionsParser> clazz : transactionsParser) {
		BankAccountTransactionsParser parser = (BankAccountTransactionsParser) clazz.newInstance();
		if (parser.test(workbook)) {
		    importData = parser.parse(workbook);
		    break;
		}
	    }
	} catch (Exception e) {
	    log.error("Error parsing excel file", e);
	}
	return importData;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static void findTransactionParsers() {
	Set<String> interfaceFilter = new HashSet<String>();
	interfaceFilter.add(BankAccountTransactionsParser.class.getCanonicalName());

	Set<String> packageFilter = new HashSet<String>();
	packageFilter.add("com.rr.mymoney.upload.parser");

	transactionsParser = new ArrayList<Class<? extends BankAccountTransactionsParser>>();
	for (Class clazz : discoverProviders(interfaceFilter, packageFilter)) {
	    transactionsParser.add(clazz);
	}
    }

    private static synchronized List<Class> discoverProviders(Set<String> interfaceFilter, Set<String> packageFilter) {
	List<Class> providers = new ArrayList<Class>();
	try {
	    Map<String, Set<Class>> results = ClassLister.findClasses(GenericFileUploadParser.class.getClassLoader(), interfaceFilter,
		    packageFilter, null, true);
	    Set<String> keys = results.keySet();
	    Iterator<String> iter = keys.iterator();
	    while (iter.hasNext()) {
		String key = iter.next();
		Set<Class> classes = results.get(key);
		Iterator<Class> iter2 = classes.iterator();
		while (iter2.hasNext()) {
		    Class clazz = iter2.next();
		    providers.add(clazz);
		}
	    }
	} catch (Exception ex) {
	    log.error("Error populating lbs data providers: ", ex);
	}
	return providers;
    }

}
